#include "strategies/SimEVKnockingStrategy.h"
#include "Query.h"

bool SimEVKnockingStrategy::decideKnock(CCardStack* hand, const GameState* gameState) {
    bool knock;
    int ownHandValue = hand->Value();
    int opponent = (gameState->getCurrPlayer() + 1) % 2;
    CCardStack oppHand = gameState->getCardsPickedUpAndHeldByPlayer(opponent);
    int unknownCards = 3 - oppHand.Size();  
    if (unknownCards == 3) {
        knock = false;
        decisionCertainty = 0;
    }
    else if (unknownCards > 0) {
        // Must simulate
        CCardStack possibleCards = gameState->getUnknownCards(gameState->getCurrPlayer());
        int maxCombinations = Query::choose(possibleCards.Size(), unknownCards);
        // Calculate the number of simulations from the given parameter;
        int numSimulations = simulationRange * maxCombinations / 100;
        // Simulate opponent hands and find winner
        int victories = 0;
        CCardStack auxStack;
        const CCard& topOfDiscard = gameState->getCardsInDiscard().back();
        // Include the top of discard pile in case the opponent benefits from it (with simulated hand)
        oppHand.Push(CCard(topOfDiscard.GetIndex()));
        for (int i = 0; i < numSimulations; i++) {
            if (possibleCards.Size() < unknownCards) {
                possibleCards.Push(auxStack);
                auxStack.Clear();
            }
            for (int j = 0; j < unknownCards; j++) {
                const CCard& card = possibleCards.RemoveCard(Query::RandomChoice(possibleCards.Size()));
                oppHand.Push(CCard(card.GetIndex()));
            }
            int oppHandValue = Query::maxValue(Query::FourCardValues(oppHand));
            if (ownHandValue > oppHandValue) {
                victories++;
            }
            auxStack.Push(oppHand.Pop(unknownCards));
        }
        float winPct = (float) victories / numSimulations;
        if (winPct > decisionThreshold) {
            knock = true;
        }
        decisionCertainty = simulationRange;
    }
    else {
        const CCard& topOfDiscard = gameState->getCardsInDiscard().back();
        // Include the top of discard pile in case the opponent benefits from it (with simulated hand)
        oppHand.Push(CCard(topOfDiscard.GetIndex()));
        int oppHandValue = Query::maxValue(Query::FourCardValues(oppHand));
        if (ownHandValue > oppHandValue) {
            knock = true;
        }
        decisionCertainty = 100;
    }
    return knock;
}
